<?php

namespace Muyuxuanpay\threePay\src\cj;

use GuzzleHttp\Client;

trait CommonTrait
{
    protected $URL = [
    'wx_pub' => 'https://pay.chanpay.com/ugtw/gateway',
    'merchant' => 'https://pay.chanpay.com/merchant/gateway',
    'alipay_wap' => 'https://ncount.hnapay.com/api/t013.htm',
    'wx_scan' => 'https://ncount.hnapay.com/api/r010.htm',
];
    protected $RESULT_CODE_SUCCESS = '0000';

    /** @var string 交易等待中 */
    protected $RESULT_CODE_PINGAN = '9999';
    //sdk相关
    protected function getEncryptionRequestBody(array $data, string $certificate):string{
        $certificate = sprintf("-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----", $certificate);

        $publicKey = openssl_get_publickey($certificate);
        if ($publicKey === false) {
            throw new \Exception('解析密钥失败');
        }
        //证书详情
        if(empty($data)){
            $jsonData = "{}";
        }else{
            $jsonData = json_encode($data);
        }
        //分割字符串加密
        $encrypt = '';
        foreach (str_split($jsonData, 117) as $str) {
            if (!openssl_public_encrypt($str, $encryptItem, $publicKey)) {
                throw new \Exception("报文签名失败");
            }
            $encrypt .= $encryptItem;
        }

        return base64_encode($encrypt);
    }
    /**
     * 新帐通报文签名
     * @param array $data
     * @param string $certificate
     * @return string
     * @throws \Exception
     */
    protected function getSign(array $data,$certificate=''): string
    {
        if(empty($certificate)){
            $certificate = $this->config['private_key'];
        }
        $certificate = sprintf("-----BEGIN RSA PRIVATE KEY-----\n%s\n-----END RSA PRIVATE KEY-----", wordwrap($certificate, 64, "\n", true));
        $encrypt = '';
        $signStr = $this->toSignStr($data);

        $privateKey = openssl_get_privatekey($certificate);

        if ($privateKey === false) {
            throw new \Exception('解析密钥失败');
        }
        if (!openssl_sign($signStr, $encrypt, $privateKey, "SHA256")) {
            throw new \Exception('报文签名失败');
        }
        return base64_encode($encrypt);
    }

    //biz_content加密参数按格式组装
    protected function toSignStr($values)
    {
        $buff = '';
        $buff .= 'method' . '=' . $values['method'] . '&';
        if(isset($values['merchant_id'])){
            $buff .= 'merchant_id' . '=' . $values['merchant_id'] . '&';
        }
        if(isset($values['acq_sp_id'])){
            $buff .= 'acq_sp_id' . '=' . $values['acq_sp_id'] . '&';
        }
        if(isset($values['function_code'])){
            $buff .= 'function_code' . '=' . $values['function_code'] . '&';
        }
        if(isset($values['product_code'])){
            $buff .= 'product_code' . '=' . $values['product_code'] . '&';
        }
//        $buff .= 'product_code' . '=' . $values['product_code'] . '&';
        $buff .= 'biz_content' . '=' . $values['biz_content'];
//        echo "<pre>";
//        print_r($buff);
//        exit;
        return trim($buff, '&');
    }
    //RSA2全局返参解密
    public function rsaDecrypt($content,$certificate=''){
        if(empty($certificate)){
            $certificate = $this->config['private_key'];
        }
        $certificate = sprintf("-----BEGIN RSA PRIVATE KEY-----\n%s\n-----END RSA PRIVATE KEY-----", wordwrap($certificate, 64, "\n", true));
        $encrypt = '';

        $privateKey = openssl_get_privatekey($certificate);

        if ($privateKey === false) {
            throw new \Exception('解析密钥失败');
        }

        $decrypted = '';
        foreach (str_split(base64_decode($content), 256) as $chunk) {
            if (!openssl_private_decrypt($chunk, $decryptData, $privateKey, OPENSSL_PKCS1_PADDING)) {
                throw new \Exception("报文解密失败");
            }
            $decrypted .= $decryptData;
        }

        return $decrypted;
    }
    //解密码时把转换后的符号替换特殊符号
    protected function urlsafe_b64decode($string) {
        $data = str_replace(array('-','_'),array('+','/'),$string);
        $mod4 = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        return base64_decode($data);
    }

    protected function post(string $url, $data)
    {
        $obj = new Client();
        $response = $obj->post($url, [
            'form_params' => $data,
        ]);
        if ($response->getStatusCode() != 200) {
            throw new \Exception('请求失败,服务器返回状态码:' . $response->getStatusCode());
        }
        $responseContent = $response->getBody()->getContents();
        if(empty($responseContent)){
            throw new \Exception('请求失败,服务器返回状态码:' . $response->getStatusCode());
        }
        $responseContent = json_decode($responseContent, true);
//        echo "<pre>";
//        print_r($responseContent);
//        exit;
        if($responseContent==''||$responseContent==null){
            throw new \Exception('请求失败,服务器返回状态码:' . $response->getStatusCode());
        }
        if($responseContent['code']!='00000'){
            throw new \Exception($responseContent['msg']??"无返回消息");
        }
        if($responseContent['sub_msg'] =='FAIL' || empty($responseContent['content'])){
            throw new \Exception($responseContent['sub_msg']??"无返回消息");
        }
        $resultDecrypt = $this->rsaDecrypt($responseContent['content'], $this->config['private_key']);
        if(empty($resultDecrypt)){
            throw new \Exception('解密失败');
        }
        $responseContent['content'] = json_decode($resultDecrypt, true);
        if(is_string($responseContent['content'])){
            $responseContent['content'] = json_decode($responseContent['content'], true);
        }
        return $responseContent;
    }

    protected function generateOrderNo(): string
    {
        return md5(uniqid('M') . substr(microtime(true), -3));
    }
    public function backSuccess()
    {
        return [
            'return_code'=>'SUCCESS',
            'return_msg'=>'OK',
        ];
    }
    public function backFail()
    {
        return [
            'return_code'=>'FAIL',
            'return_msg'=>'FAIL',
        ];
    }
}